﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Management;
using System.IO;

namespace SerialAssist
{
    public partial class frmMain : Form
    {

        enum CharTypes
        {
            ASCII,
            HEX,
            BIN,
        }

        class Data
        {
            private List<byte> Bytes;

            public int Count
            {
                get
                {
                    return Bytes.Count;
                }
            }

            public byte this[int index]
            {
                get
                {
                    return Bytes[index];
                }
            }

            public Data()
            {
                Bytes = new List<byte>();
            }

            public Data(byte b)
            {
                Bytes = new List<byte>();
                Bytes.Add(b);
            }

            public Data(IEnumerable<byte> bytes)
            {
                Bytes = new List<byte>();
                Bytes.AddRange(bytes);
            }

            public int Add(byte b)
            {
                int n = Bytes.Count;
                Bytes.Add(b);
                return n;
            }

            public int AddRange(IEnumerable<byte> bytes)
            {
                int n = Bytes.Count;
                Bytes.AddRange(bytes);
                return n;
            }

            public void Trunck()
            {// 对数据进行截断，以满足获取 Unicode 编码时的需求
                if (Bytes.Count % 2 != 0)
                {
                    Bytes.RemoveAt(Bytes.Count - 1);
                }
            }

            public void Clear()
            {
                Bytes.Clear();
            }

            public void RemoveAt(int index)
            {
                Bytes.RemoveAt(index);
            }

            public byte[] GetData()
            {
                return Bytes.ToArray();
            }

            public byte[] GetData(int index, int count)
            {
                List<byte> bytes = new List<byte>();
                bytes.AddRange(Bytes);
                if (index > 0)
                {
                    bytes.RemoveRange(0, index);
                }
                return bytes.Take(count).ToArray();
            }

            public string GetAscii()
            {
                List<byte> bytes = new List<byte>();
                bytes.AddRange(Bytes.ToArray());
                while (bytes.Contains(0))
                    bytes.Remove(0);
                return Encoding.ASCII.GetString(bytes.ToArray());
            }

            public string GetAscii(int index, int count)
            {
                List<byte> bytes = new List<byte>();
                bytes.AddRange(Bytes.ToArray());
                while (bytes.Contains(0))
                    bytes.Remove(0);

                return Encoding.ASCII.GetString(bytes.ToArray(), index, count);
            }

            public string GetHex()
            {
                StringBuilder sb = new StringBuilder();
                foreach (byte b in Bytes)
                {
                    sb.Append(string.Format("{0:X2} ", b));
                }

                return sb.ToString();
            }

            public string GetHex(int index, int count)
            {
                StringBuilder sb = new StringBuilder();
                int end = index + count;
                for (int i = index; i < end; i++)
                {
                    sb.Append(string.Format("{0:X2} ", Bytes[i]));
                }

                return sb.ToString();
            }

            public string GetBin()
            {
                StringBuilder sb = new StringBuilder();
                string temp;
                foreach (byte b in Bytes)
                {
                    temp = Convert.ToString(b, 2);
                    if (temp.Length < 8)
                    {
                        int n = 8 - temp.Length;
                        while (n > 0)
                        {
                            sb.Append("0");
                            n--;
                        }

                    }
                    sb.Append(temp + " ");
                }
                return sb.ToString();
            }

            public string GetBin(int index, int count)
            {
                StringBuilder sb = new StringBuilder();
                string temp;
                int end = index + count;
                for (int i = index; i < end; i++)
                {
                    temp = Convert.ToString(Bytes[i], 2);
                    if (temp.Length < 8)
                    {
                        int n = 8 - temp.Length;
                        while (n > 0)
                        {
                            sb.Append("0");
                            n--;
                        }

                    }
                    sb.Append(temp + " ");
                }
                return sb.ToString();
            }

            public string GetUnicode()
            {
                return Encoding.Unicode.GetString(Bytes.ToArray());
            }

            public string GetUnicode(int index, int count)
            {
                return Encoding.Unicode.GetString(Bytes.ToArray(), index, count);
            }
        }


        /// <summary>
        /// 枚举win32 api
        /// </summary>
        public enum HardwareEnum
        {
            // 硬件
            Win32_Processor, // CPU 处理器
            Win32_PhysicalMemory, // 物理内存条
            Win32_Keyboard, // 键盘
            Win32_PointingDevice, // 点输入设备，包括鼠标。
            Win32_FloppyDrive, // 软盘驱动器
            Win32_DiskDrive, // 硬盘驱动器
            Win32_CDROMDrive, // 光盘驱动器
            Win32_BaseBoard, // 主板
            Win32_BIOS, // BIOS 芯片
            Win32_ParallelPort, // 并口
            Win32_SerialPort, // 串口
            Win32_SerialPortConfiguration, // 串口配置
            Win32_SoundDevice, // 多媒体设置，一般指声卡。
            Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
            Win32_USBController, // USB 控制器
            Win32_NetworkAdapter, // 网络适配器
            Win32_NetworkAdapterConfiguration, // 网络适配器设置
            Win32_Printer, // 打印机
            Win32_PrinterConfiguration, // 打印机设置
            Win32_PrintJob, // 打印机任务
            Win32_TCPIPPrinterPort, // 打印机端口
            Win32_POTSModem, // MODEM
            Win32_POTSModemToSerialPort, // MODEM 端口
            Win32_DesktopMonitor, // 显示器
            Win32_DisplayConfiguration, // 显卡
            Win32_DisplayControllerConfiguration, // 显卡设置
            Win32_VideoController, // 显卡细节。
            Win32_VideoSettings, // 显卡支持的显示模式。

            // 操作系统
            Win32_TimeZone, // 时区
            Win32_SystemDriver, // 驱动程序
            Win32_DiskPartition, // 磁盘分区
            Win32_LogicalDisk, // 逻辑磁盘
            Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
            Win32_LogicalMemoryConfiguration, // 逻辑内存配置
            Win32_PageFile, // 系统页文件信息
            Win32_PageFileSetting, // 页文件设置
            Win32_BootConfiguration, // 系统启动配置
            Win32_ComputerSystem, // 计算机信息简要
            Win32_OperatingSystem, // 操作系统信息
            Win32_StartupCommand, // 系统自动启动程序
            Win32_Service, // 系统安装的服务
            Win32_Group, // 系统管理组
            Win32_GroupUser, // 系统组帐号
            Win32_UserAccount, // 用户帐号
            Win32_Process, // 系统进程
            Win32_Thread, // 系统线程
            Win32_Share, // 共享
            Win32_NetworkClient, // 已安装的网络客户端
            Win32_NetworkProtocol, // 已安装的网络协议
            Win32_PnPEntity,//all device
        }











        private System.Threading.Timer _tmrRefreshPorts;
        private Dictionary<int, string> _PortList = new Dictionary<int, string>();
        private bool _CheckPorts = false;
        private int _CurrentOpenedPort = -1;

        //List<byte> _ReceivBuf = new List<byte>();

        private CharTypes _RecvCharDisplayType = CharTypes.ASCII;
        private CharTypes _SendCharType = CharTypes.ASCII;

        //private List<Data> _DataBuf = new List<Data>();
        private Data _DataBuf = new Data();
        private int _ReceivedCount = 0;
        private int _SentCount = 0;

        bool _isUnicode = false;

        bool _IsDisplayPaused = false;

        Dictionary<string, string> _Preset = new Dictionary<string, string>();

        byte[] _SendBuf;
        bool _SendBufChanged = true;

        int _Bps = 0;
        bool _DontAskStopRecvDueToTraffic = false;
        bool _TerminateRecev = false;
        bool _IsReceiving = false;

        ESP8266 _Esp8266 = new ESP8266();
        










        /// <summary>
        /// WMI取硬件信息
        /// </summary>
        /// <param name="hardType"></param>
        /// <param name="propKey"></param>
        /// <returns></returns>
        public static List<string> MulGetHardwareInfo(HardwareEnum hardType, string propKey)
        {

            List<string> strs = new List<string>();


            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    string name;
                    foreach (var hardInfo in hardInfos)
                    {
                        name = (string)hardInfo.Properties[propKey].Value;
                        if (name == null)
                            continue;

                        if (name.Contains("COM"))
                        {
                            strs.Add(name);
                        }

                    }
                    searcher.Dispose();
                }
                return strs;
            }
            catch
            {
                return null;
            }
        }

        private void thdPortRefresh(object obj)
        {
            List<string> portNameList = new List<string>();

            Dictionary<int, string> ports = new Dictionary<int, string>();

            Regex r = new Regex(@"\bCOM\d{1,3}\b", RegexOptions.Compiled);

            bool portChanged = false;
            bool portDisapeared = false;
            bool firstRun = _PortList.Count == 0;
            int cbbPortDropDownWidth = 0;

            _CheckPorts = true;

            _tmrRefreshPorts.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);

            //throw (new ArgumentNullException("Fuck"));

            portNameList.AddRange(System.IO.Ports.SerialPort.GetPortNames());
            portNameList.Sort();

            //通过WMI获取COM端口
            List<string> portDriverNameList = MulGetHardwareInfo(HardwareEnum.Win32_PnPEntity, "Name");

            if (portDriverNameList == null || portDriverNameList.Count == 0)
            {
                _tmrRefreshPorts.Change(200, 200);
                _CheckPorts = false;
                return;
            }

            foreach (string str in portDriverNameList)
            {
                int portNameInDriverName=-1;
                try
                {
                    portNameInDriverName = Convert.ToInt32(r.Match(str).Value.Replace("COM", string.Empty));
                }
                catch
                {
                    //MessageBox.Show(str);
                    //MessageBox.Show(r.Match(str).Value);
                    continue;
                }

                ports.Add(portNameInDriverName, str);
                if (firstRun)
                {
                    if (_PortList.Keys.Contains(portNameInDriverName) == false)
                        _PortList.Add(portNameInDriverName, str);
                }
            }

            if (firstRun)
            {
                portChanged = true;
                firstRun = false;
            }
            else
            {
                if (_PortList.Count != ports.Count)
                {
                    portChanged = true;
                    if (_CurrentOpenedPort != -1)
                    {
                        foreach (int portName in _PortList.Keys)
                        {
                            if (ports.Keys.Contains(portName) == false)
                            {
                                if (_CurrentOpenedPort == portName)
                                {
                                    portDisapeared = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if (portChanged)
            {
                ports = ports.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
                _PortList.Clear();
                _PortList = null;
                _PortList = ports;
                using (Bitmap bmp = new Bitmap(1, 1))
                {
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        float width;
                        foreach (string str in portDriverNameList)
                        {
                            width = g.MeasureString(str, cbbPortName.Font).Width;
                            if (width > cbbPortDropDownWidth)
                            {
                                cbbPortDropDownWidth = (int)width + 1;
                            }
                        }
                    }
                }

                this.Invoke(new MethodInvoker(() =>
                {
                    cbbPortName.Items.Clear();
                    cbbPortName.Items.AddRange(ports.Values.ToArray());
                    cbbPortName.DropDownWidth = cbbPortDropDownWidth;
                }));
            }

            if (portDisapeared)
            {
                this.Invoke(new MethodInvoker(() =>
                {
                    pnlSettings.Enabled = true;
                    ckbDtr.Enabled = false;
                    ckbRts.Enabled = false;
                    pnlPortStatus.BackColor = Color.DimGray;
                    btnOpenPort.Text = "打开";
                    lblPortName.Text = "端  口";
                    cbbPortName.Visible = true;

                    MessageBox.Show("端口意外被移除。如果您使用的是 USB 转串口，请检查 USB 连接。");
                }));
            }
            _tmrRefreshPorts.Change(200, 200);
            _CheckPorts = false;
        }


        private void OpenPort(int baudRate,bool registerEvent)
        {
            if (serialPort == null || serialPort.IsOpen)
                return;

            serialPort.BaudRate = baudRate;
            serialPort.StopBits = (System.IO.Ports.StopBits)(cbbStopBits.SelectedIndex + 1);
            serialPort.DataBits = Convert.ToInt32(cbbDataBits.Text);
            serialPort.Parity = (System.IO.Ports.Parity)cbbParatyBits.SelectedIndex;
            serialPort.PortName = "COM" + _PortList.Keys.ToArray()[cbbPortName.SelectedIndex];

            try
            {
                serialPort.Open();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return;
            }

            pnlSettings.Enabled = false;
            ckbDtr.Enabled = true;
            ckbRts.Enabled = true;
            pnlPortStatus.BackColor = Color.Red;
            btnSend.Enabled = true;

            if (registerEvent)
                serialPort.DataReceived += serialPort_DataReceived;

            btnOpenPort.Text = "关闭";
            lblPortStatus.Text = "打开";
            lblPortName.Text = "端  口：COM" + _PortList.Keys.ToArray()[cbbPortName.SelectedIndex];
            cbbPortName.Visible = false;

            _DontAskStopRecvDueToTraffic = false;

            _CurrentOpenedPort = Convert.ToInt32(serialPort.PortName.Replace("COM", string.Empty));

            tmrTraffic.Enabled = true;
            _TerminateRecev = false;
        }

        private void ClosePort()
        {
            if (serialPort == null || serialPort.IsOpen == false)
                return;

            tmrAutoSend.Enabled = false;
            btnSend.Text = "发送";

            _TerminateRecev = true;
            serialPort.DataReceived -= serialPort_DataReceived;




            while (_IsReceiving)
            {
                Application.DoEvents();
            }

            serialPort.Close();

            pnlSettings.Enabled = true;
            ckbDtr.Enabled = false;
            ckbRts.Enabled = false;
            pnlPortStatus.BackColor = Color.DimGray;
            btnSend.Enabled = false;

            btnOpenPort.Text = "打开";
            lblPortStatus.Text = "关闭";
            lblPortName.Text = "端  口";
            cbbPortName.Visible = true;

            _CurrentOpenedPort = -1;

            tmrTraffic.Enabled = false;
        }

        private void UpdateContent(byte[] newBytes)
        {
            lblRecvCount.Text = _ReceivedCount.ToString();

            int addPoint = _DataBuf.AddRange(newBytes);

            if (_IsDisplayPaused)
                return;

            switch (_RecvCharDisplayType)
            {
                case CharTypes.ASCII:
                    {
                        string str;
                        if (ckbUnicode.Checked)
                            str = Encoding.Unicode.GetString(newBytes);
                        else
                            str = Encoding.ASCII.GetString(newBytes);
                        txbRecv.AppendText(str);
                        break;
                    }
                case CharTypes.HEX:
                    {
                        txbRecv.AppendText(_DataBuf.GetHex(addPoint, newBytes.Length));
                        break;
                    }
                case CharTypes.BIN:
                    {
                        txbRecv.AppendText(_DataBuf.GetBin(addPoint, newBytes.Length));
                        break;
                    }
            }
            txbRecv.ScrollToCaret();
        }

        private void UpdateContent(Data data)
        {
            //txbRecv.Clear();
            switch (_RecvCharDisplayType)
            {
                case CharTypes.ASCII:
                    {
                        if (_isUnicode)
                            txbRecv.Text = data.GetUnicode();
                        else
                            txbRecv.Text = data.GetAscii();

                        break;
                    }
                case CharTypes.HEX:
                    {
                        txbRecv.Text = data.GetHex();
                        break;
                    }
                case CharTypes.BIN:
                    {
                        txbRecv.Text = data.GetBin();
                        break;
                    }
            }
        }


        void AddPreset(string content)
        {
            frmAdd frm = new frmAdd();
            frm.Content = content;

        start:
            if (frm.ShowDialog() == DialogResult.Cancel)
                return;

            content = frm.Content;
            string name = frm.ContentName;

            if (_Preset.Keys.Contains(name))
            {
                MessageBox.Show("已包含该名称的数据！");
                goto start;
            }

            _Preset.Add(name, content);
            _Preset = _Preset.OrderBy(o => (o.Key)).ToDictionary(o => o.Key, o => o.Value);

            ListViewItem item = new ListViewItem(name);
            item.SubItems.Add(new ListViewItem.ListViewSubItem(item, content));

            lstvPreset.Items.Add(item);

            SavePreset();
            //增加对预设唯一性的校验
        }

        void Modifyreset(ListViewItem item, string name, string content)
        {
            string newName;
            string newContent;

            frmAdd frm = new frmAdd();
            frm.Content = content;
            frm.ContentName = name;
            frm.Modify = true;
            if (frm.ShowDialog() == DialogResult.Cancel)
                return;

            newContent = frm.Content;
            newName = frm.ContentName;

            if (newName != name)
            {
                _Preset.Remove(name);
                _Preset.Add(newName, newContent);
                _Preset = _Preset.OrderBy(o => (o.Key)).ToDictionary(o => o.Key, o => o.Value);
            }
            else
            {
                _Preset[name] = newContent;
            }
            item.Text = newName;
            item.SubItems[1].Text = newContent;

            SavePreset();
        }

        void SavePreset()
        {
            string path = Application.StartupPath + "\\preset.txt";
            FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);

            foreach (string name in _Preset.Keys)
            {
                sw.Write(string.Format("{0},{1}\r\n", name, _Preset[name]));
            }

            sw.Close();
            fs.Close();
        }

        void LoadFirmware()
        {
            string path = Application.StartupPath + "\\firmware.txt";

            if (System.IO.File.Exists(path) == false)
            {
                txbImg1Path.BackColor = Color.Maroon;
                txbImg1Path.ForeColor = Color.Yellow;
                txbImg2Path.BackColor = Color.Maroon;
                txbImg2Path.ForeColor = Color.Yellow;
                return;
            }

            string[] firmwares=File.ReadAllLines(path);

            if (File.Exists(firmwares[0]))
            {
                txbImg1Path.Text = firmwares[0];
                txbImg1Path.BackColor = Color.LightGreen;
                txbImg1Path.ForeColor = Color.Black;
            }
            else
            {
                txbImg1Path.BackColor = Color.Maroon;
                txbImg1Path.ForeColor = Color.Yellow;
            }

            if (File.Exists(firmwares[1]))
            {
                txbImg2Path.Text = firmwares[1];
                txbImg2Path.BackColor = Color.LightGreen;
                txbImg2Path.ForeColor = Color.Black;
            }
            else
            {
                txbImg2Path.BackColor = Color.Maroon;
                txbImg2Path.ForeColor = Color.Yellow;
            }
        }

        void SaveFirmwares()
        {
            string path = Application.StartupPath + "\\firmware.txt";
            string[] firmwares = new string[2];
            firmwares[0] = txbImg1Path.Text;
            firmwares[1] = txbImg2Path.Text;

            File.WriteAllLines(path, firmwares);
        }

        void LoadPreset()
        {
            string path = Application.StartupPath + "\\preset.txt";

            if (System.IO.File.Exists(path) == false)
                return;

            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(fs);

            string[] str;
            string line;

            if (_Preset == null)
                _Preset = new Dictionary<string, string>();
            else
                _Preset.Clear();

            lstvPreset.BeginUpdate();
            while (sr.EndOfStream == false)
            {
                line = sr.ReadLine();
                if (line.Contains(",") == false)
                    continue;

                str = line.Split(',');
                if (str.Length != 2)
                    continue;

                _Preset.Add(str[0], str[1]);

                ListViewItem item = new ListViewItem(str[0]);
                ListViewItem.ListViewSubItem subItem = new ListViewItem.ListViewSubItem(item, str[1]);
                item.SubItems.Add(subItem);
                lstvPreset.Items.Add(item);
            }
            lstvPreset.EndUpdate();

            sr.Close();
            fs.Close();
        }


        void Send(string str)
        {
            if (serialPort.IsOpen == false)
                return;

            List<byte> bytes = new List<byte>();
            if (_SendBufChanged)
            {
                _SendBufChanged = false;

                switch (_SendCharType)
                {
                    case CharTypes.ASCII:
                        {
                            if (ckbUnicode.Checked)
                                bytes.AddRange(Encoding.Unicode.GetBytes(str));
                            else
                                bytes.AddRange(Encoding.ASCII.GetBytes(str));
                            break;
                        }
                    case CharTypes.BIN:
                    case CharTypes.HEX:
                        {
                            string[] val = str.Trim().Replace("\r", string.Empty).Replace("\n", " ").Split(' ');
                            try
                            {
                                if (_SendCharType == CharTypes.BIN)
                                {
                                    foreach (string bin in val)
                                    {
                                        if (bin == string.Empty)
                                            continue;
                                        bytes.Add(Convert.ToByte(bin, 2));
                                    }
                                }
                                else
                                {
                                    foreach (string hex in val)
                                    {
                                        if (hex == string.Empty)
                                            continue;

                                        if (hex.Length <= 2)
                                        {
                                            bytes.Add(Convert.ToByte(hex, 16));
                                        }
                                        else if (hex.Length <= 4)
                                        {
                                            bytes.AddRange(BitConverter.GetBytes(Convert.ToUInt16(hex, 16)));
                                        }
                                        else if (hex.Length <= 8)
                                        {
                                            bytes.AddRange(BitConverter.GetBytes(Convert.ToUInt32(hex, 16)));
                                        }
                                        else if (hex.Length <= 16)
                                        {
                                            bytes.AddRange(BitConverter.GetBytes(Convert.ToUInt64(hex, 16)));
                                        }
                                        else
                                        {
                                            throw (new Exception());
                                        }

                                    }
                                }
                            }
                            catch
                            {
                                MessageBox.Show("请输入合法的数据，每个数据间以空格分开（如二进制 10101010 01010101，十六进制 DD CC BB AA99 88776655）。");
                                return;
                            }
                            break;
                        }
                }
                _SendBuf = bytes.ToArray();
            }

            serialPort.Write(_SendBuf, 0, _SendBuf.Length);

            _SentCount += _SendBuf.Length;

            lblSendCount.Text = _SentCount.ToString();

            Application.DoEvents();
        }




        void TranslateSendToAscii()
        {
            string txt = txbSend.Text;
            string[] values;
            List<byte> bytes = new List<byte>();
            byte b = 0;
            while (txt.Contains("  "))
            {
                txt = txt.Replace("  ", " ");
            }
            values = txt.Split(' ');

            foreach (string str in values)
            {
                try
                {
                    if (_SendCharType == CharTypes.BIN)
                        b = Convert.ToByte(str, 2);
                    else //if (_SendCharType == CharTypes.HEX)
                        b = Convert.ToByte(str, 16);
                }
                catch
                {
                    continue;
                }
                bytes.Add(b);
            }
            if (_isUnicode)
            {
                txbSend.Text = Encoding.Unicode.GetString(bytes.ToArray());
            }
            else
            {
                txbSend.Text = Encoding.ASCII.GetString(bytes.ToArray());
            }
        }

        void TranslateSendToHex()
        {
            string txt = txbSend.Text;
            string[] values;
            List<byte> bytes = new List<byte>();
            byte b = 0;
            StringBuilder sb = new StringBuilder();

            if (_SendCharType==CharTypes.BIN)
            {
                while (txt.Contains("  "))
                {
                    txt = txt.Replace("  ", " ");
                }
                values = txt.Split(' ');

                foreach (string str in values)
                {
                    try
                    {
                        b = Convert.ToByte(str, 2);
                    }
                    catch
                    {
                        continue;
                    }
                    bytes.Add(b);
                }
            }
            else if(_SendCharType==CharTypes.ASCII)
            {
                if(_isUnicode)
                {
                    bytes.AddRange(Encoding.Unicode.GetBytes(txt));
                }
                else
                {
                    bytes.AddRange(Encoding.ASCII.GetBytes(txt));
                }
            }

            foreach(byte bb in bytes)
            {
                sb.Append(string.Format("{0:X2} ", bb));
            }

            txbSend.Text = sb.ToString();
        }

        void TranslateSendToBin()
        {
            string txt = txbSend.Text;
            string[] values;
            List<byte> bytes = new List<byte>();
            byte b = 0;
            StringBuilder sb = new StringBuilder();

            if (_SendCharType == CharTypes.HEX)
            {
                while (txt.Contains("  "))
                {
                    txt = txt.Replace("  ", " ");
                }
                values = txt.Split(' ');

                foreach (string str in values)
                {
                    try
                    {
                        b = Convert.ToByte(str, 16);
                    }
                    catch
                    {
                        continue;
                    }
                    bytes.Add(b);
                }
            }
            else if(_SendCharType == CharTypes.ASCII)
            {
                if (_isUnicode)
                {
                    bytes.AddRange(Encoding.Unicode.GetBytes(txt));
                }
                else
                {
                    bytes.AddRange(Encoding.ASCII.GetBytes(txt));
                }
            }

            string temp;
            foreach (byte bb in bytes)
            {
                temp = Convert.ToString(bb, 2);
                if (temp.Length < 8)
                {
                    int n = 8 - temp.Length;
                    while (n > 0)
                    {
                        sb.Append("0");
                        n--;
                    }

                }
                sb.Append(temp + " ");
            }

            txbSend.Text = sb.ToString();
        }

        void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (_TerminateRecev)
                return;

            _IsReceiving = true;

            int bytesToRead = serialPort.BytesToRead;
            byte[] bytes;

            if (_isUnicode)
            {
                if (bytesToRead % 2 != 0)
                {
                    bytesToRead--;
                }
                //                 while(bytesToRead%2!=0)
                //                 {
                //                     System.Threading.Thread.Sleep(1);
                //                     bytesToRead = serialPort.BytesToRead;
                //                     Application.DoEvents();
                //                 }
            }

            bytes = new byte[bytesToRead];
            serialPort.Read(bytes, 0, bytesToRead);
            _ReceivedCount += bytesToRead;
            _Bps += bytesToRead;
            this.Invoke(new MethodInvoker(() =>
            {
                UpdateContent(bytes);
            }));

            _IsReceiving = false;
        }





        public frmMain()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _tmrRefreshPorts = new System.Threading.Timer(thdPortRefresh, null, 0, 200);
            cbbBaudRate.SelectedIndex = 8;
            cbbDataBits.SelectedIndex = 0;
            cbbParatyBits.SelectedIndex = 0;
            cbbStopBits.SelectedIndex = 0;

            _Esp8266.Esp8266FlashStateChanged += Esp_Esp8266FlashStateChanged;

            LoadPreset();
            LoadFirmware();
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            _tmrRefreshPorts.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            tmrAutoSend.Enabled = false;

            serialPort.DataReceived -= serialPort_DataReceived;
            if (serialPort.IsOpen)
                serialPort.Close();

            while (_CheckPorts || serialPort.IsOpen)
            {
                System.Threading.Thread.Sleep(5);
                Application.DoEvents();
            }
        }

        private void btnOpenPort_Click(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                ClosePort();
            }
            else
            {
                if (cbbPortName.SelectedIndex < 0)
                {
                    MessageBox.Show("还没有选择端口");
                    return;
                }
                OpenPort(Convert.ToInt32(cbbBaudRate.Text), true);
            }
        }

        private void 预设数据ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            预设数据ToolStripMenuItem.Checked = !预设数据ToolStripMenuItem.Checked;
            lstvPreset.Visible = 预设数据ToolStripMenuItem.Checked;
        }

        private void ckbRts_CheckedChanged(object sender, EventArgs e)
        {
            serialPort.RtsEnable = ckbRts.Checked;
        }

        private void ckbDtr_CheckedChanged(object sender, EventArgs e)
        {
            serialPort.DtrEnable = ckbDtr.Checked;
        }

        private void rdbAscii_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbAscii.Checked)
            {
                _RecvCharDisplayType = CharTypes.ASCII;

                lstvRecv.Columns[0].Text = "ASCII";
                lstvRecv.Columns[1].Text = "HEX";
                lstvRecv.Columns[2].Text = "BIN";

                lstvRecv.Items.Clear();

                UpdateContent(_DataBuf);
            }
        }

        private void rdbHex_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbHex.Checked)
            {
                _RecvCharDisplayType = CharTypes.HEX;

                lstvRecv.Columns[0].Text = "HEX";
                lstvRecv.Columns[1].Text = "BIN";
                lstvRecv.Columns[2].Text = "ASCII";

                lstvRecv.Items.Clear();

                UpdateContent(_DataBuf);
            }
        }

        private void rdbBin_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbBin.Checked)
            {
                _RecvCharDisplayType = CharTypes.BIN;
                lstvRecv.Columns[0].Text = "BIN";
                lstvRecv.Columns[1].Text = "HEX";
                lstvRecv.Columns[2].Text = "ASCII";

                lstvRecv.Items.Clear();

                UpdateContent(_DataBuf);
            }
        }

        private void rdbAsciiSend_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbAsciiSend.Checked)
            {
                if (ckbChangeWithASCII_HEX_BIN.Checked)
                    TranslateSendToAscii();

                _SendCharType = CharTypes.ASCII;
                _SendBufChanged = true;
            }
        }

        private void rdbHexSend_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbHexSend.Checked)
            {
                if (ckbChangeWithASCII_HEX_BIN.Checked)
                    TranslateSendToHex();

                _SendCharType = CharTypes.HEX;
                _SendBufChanged = true;
            }
        }

        private void rdbBinSend_CheckedChanged(object sender, EventArgs e)
        {
            if (rdbBinSend.Checked)
            {
                if (ckbChangeWithASCII_HEX_BIN.Checked)
                    TranslateSendToBin();

                _SendCharType = CharTypes.BIN;
                _SendBufChanged = true;
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            _TerminateRecev = false;

            if (ckbAutoSend.Checked)
            {
                tmrAutoSend.Interval = (int)nmAutoSendInterval.Value;
                if (tmrAutoSend.Enabled == false)
                {
                    tmrAutoSend.Enabled = true;
                    btnSend.Text = "停止";
                    _DontAskStopRecvDueToTraffic = false;
                }
                else
                {
                    tmrAutoSend.Enabled = false;
                    btnSend.Text = "发送";
                }
            }
            else
                Send(txbSend.Text);
        }

        private void btnClearRecv_Click(object sender, EventArgs e)
        {
            txbRecv.Clear();
            _DataBuf.Clear();
            lstvRecv.Items.Clear();
        }

        private void ckbUnicode_CheckedChanged(object sender, EventArgs e)
        {
            if (ckbUnicode.Checked)
            {
                if (MessageBox.Show("您已经选择了 Unicode 模式。现在将对已接收的数据进行处理，以便获取 Unicode 字符串。这可能导致丢失现有数据的最后一个字节，您确定吗？", "更改字符模式", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.No)
                {
                    ckbUnicode.Checked = false;
                    return;
                }
                else
                {
                    _DataBuf.Trunck();
                    _SendBufChanged = true;
                }
            }

            if (_isUnicode != ckbUnicode.Checked)
            {
                _isUnicode = ckbUnicode.Checked;
                lstvRecv.Items.Clear();
                UpdateContent(_DataBuf);
            }
        }

        private void 添加到列表ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //             lstvPreset.Visible = true;
            //             预设数据ToolStripMenuItem.Checked = true;
            tabControl1.SelectedIndex = 1;
            AddPreset(txbSend.Text);
        }

        private void txbSend_KeyPress(object sender, KeyPressEventArgs e)
        {
            switch ((int)e.KeyChar)
            {
                case 1:
                    {// Ctrl-A
                        txbSend.SelectAll();
                        break;
                    }
            }

        }

        private void 添加ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddPreset(string.Empty);
        }

        private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lstvPreset.SelectedItems.Count == 0)
                return;

            lstvPreset.BeginUpdate();
            foreach (ListViewItem item in lstvPreset.SelectedItems)
            {
                lstvPreset.Items.Remove(item);
            }
            lstvPreset.EndUpdate();
        }

        private void 修改ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lstvPreset.SelectedItems.Count == 0)
                return;

            ListViewItem item = lstvPreset.SelectedItems[0];
            Modifyreset(item, item.Text, item.SubItems[1].Text);
        }

        private void 插入到发送ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lstvPreset.SelectedItems.Count == 0)
                return;

            foreach (ListViewItem item in lstvPreset.SelectedItems)
            {
                if ((rdbHexSend.Checked || rdbBinSend.Checked) && txbSend.Text.EndsWith(" ") == false)
                {
                    txbSend.AppendText(" ");
                }
                txbSend.AppendText(item.SubItems[1].Text);
            }
        }

        private void lstvPreset_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (lstvPreset.SelectedItems.Count == 0)
                return;

            if (e.Button == MouseButtons.Left)
            {
                foreach (ListViewItem item in lstvPreset.SelectedItems)
                {
                    // 发送选中数据
                    Send(item.SubItems[1].Text);
                }
            }
        }

        private void 复制ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(txbSend.SelectedText);
            //txbSend.SelectedText
        }

        private void 粘贴ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int start = txbSend.SelectionStart;
            int len = txbSend.SelectionLength;


            string str = Clipboard.GetText();
            txbSend.Text = txbSend.Text.Remove(start, len).Insert(start, str);
            txbSend.SelectionStart = start + str.Length;
            //txbSend.SelectionStart
        }

        private void ckbAutoSend_CheckedChanged(object sender, EventArgs e)
        {
            if (ckbAutoSend.Checked)
                tmrAutoSend.Interval = (int)nmAutoSendInterval.Value;
            else
            {
                tmrAutoSend.Enabled = false;
                btnSend.Text = "发送";
            }

        }

        private void tmrAutoSend_Tick(object sender, EventArgs e)
        {
            Send(txbSend.Text);
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            //预设数据ToolStripMenuItem_Click(null, null);
            //lstvPreset.Visible = true;
            //预设数据ToolStripMenuItem.Checked = true;
            tabControl1.SelectedIndex = 1;
            AddPreset(txbSend.Text);
        }

        private void 隐藏ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            预设数据ToolStripMenuItem_Click(null, null);
        }

        private void nmAutoSendInterval_ValueChanged(object sender, EventArgs e)
        {
            tmrAutoSend.Interval = (int)nmAutoSendInterval.Value;
        }

        private void ckbPauseDisplay_CheckedChanged(object sender, EventArgs e)
        {
            _IsDisplayPaused = ckbPauseDisplay.Checked;
        }

        private void btnClearSatistic_ButtonClick(object sender, EventArgs e)
        {
            _SentCount = 0;
            _ReceivedCount = 0;
            lblRecvCount.Text = "0";
            lblSendCount.Text = "0";
        }

        private void 字符串ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".txt";
            saveFileDialog1.Filter = "文本文件|*.txt";

            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);

            sw.Write(_DataBuf.GetAscii(), Encoding.ASCII);

            sw.Close();
            fs.Close();
        }

        private void unicode文本文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".txt";
            saveFileDialog1.Filter = "文本文件|*.txt";

            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs, Encoding.Unicode);

            sw.Write(_DataBuf.GetUnicode());

            sw.Close();
            fs.Close();
        }

        private void 十六进制字符串ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".txt";
            saveFileDialog1.Filter = "文本文件|*.txt";

            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);

            sw.Write(_DataBuf.GetHex());

            sw.Close();
            fs.Close();
        }

        private void 二进制字符串ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".txt";
            saveFileDialog1.Filter = "文本文件|*.txt";

            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);

            sw.Write(_DataBuf.GetBin());

            sw.Close();
            fs.Close();
        }

        private void 二进制文件ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = ".dat";
            saveFileDialog1.Filter = "数据文件|*.dat";

            if (saveFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write);
            BinaryWriter bw = new BinaryWriter(fs);

            bw.Write(_DataBuf.GetData());

            bw.Close();
            fs.Close();
        }

        private void 全选ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            txbRecv.SelectAll();
        }

        private void 复制ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(txbRecv.SelectedText);
        }

        private void 清除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            btnClearRecv_Click(null, null);
        }

        private void txbSend_TextChanged(object sender, EventArgs e)
        {
            _SendBufChanged = true;
        }

        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void txbRecv_MouseUp(object sender, MouseEventArgs e)
        {
            if (txbRecv.SelectionLength == 0)
            {
                lstvRecv.Items.Clear();
                return;
            }
            List<ListViewItem> items = new List<ListViewItem>();
            string str = txbRecv.SelectedText;
            byte[] bytes;
            

            lstvRecv.BeginUpdate();
            lstvRecv.Items.Clear();
            switch (_RecvCharDisplayType)
            {
                case CharTypes.ASCII:
                    {
                        StringBuilder sb = new StringBuilder();
                        if (_isUnicode == false)
                        {
                            lstvRecv.Columns[0].Text = "ASCII";
                            lstvRecv.Columns[1].Text = "HEX";
                            lstvRecv.Columns[2].Text = "BIN";
                            
                            bytes = Encoding.ASCII.GetBytes(str);
                            
                            int i = 0;
                            foreach (char c in str)
                            {
                                string s;
                                if (c == ' ')
                                    s = "空格";
                                else
                                    s = c.ToString();

                                string bin = Convert.ToString(bytes[i], 2);
                                sb.Clear();
                                if (bin.Length < 8)
                                {
                                    int n = 8 - bin.Length;
                                    while (n > 0)
                                    {
                                        sb.Append("0");
                                        n--;
                                    }
                                }
                                sb.Append(bin);
                                sb.Insert(4, ' ');

                                ListViewItem item = new ListViewItem(s);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, string.Format("{0:X2}", bytes[i++]));
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item, sb.ToString());
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);
                            }
                        }
                        else
                        {
                            lstvRecv.Columns[0].Text = "Unicode";
                            lstvRecv.Columns[1].Text = "HEX";
                            lstvRecv.Columns[1].Text = "BIN";

                            bytes = Encoding.Unicode.GetBytes(str);
                            int i = 0;
                            foreach (char c in str)
                            {
                                string s;
                                if (c == ' ')
                                    s = "空格";
                                else
                                    s = c.ToString();
                                
                                sb.Clear();
                                string bin;
                                for (int j = 0; j < 2; j++)
                                {
                                    bin = Convert.ToString(bytes[i + j], 2);

                                    if (bin.Length < 8)
                                    {
                                        int n = 8 - bin.Length;
                                        while (n > 0)
                                        {
                                            sb.Append("0");
                                            n--;
                                        }
                                    }

                                    sb.Append(bin + "    ");
                                }
                                sb.Insert(4, ' ');
                                sb.Insert(17, ' ');
                                //0000 0000  0000 0000

                                ListViewItem item = new ListViewItem(s);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, string.Format("{0:X2} {1:X2}", bytes[i], bytes[i + 1]));
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item, sb.ToString());
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);

                                i += 2;
                            }
                        }
                        break;
                    }
                case CharTypes.HEX:
                    {
                        List<string> hexes = new List<string>(str.Trim().Split(' '));
                        StringBuilder sb = new StringBuilder();

                        for (int i = 0; i < hexes.Count; )
                        {
                            if (hexes[i].Length != 2)
                                hexes.RemoveAt(i);
                            else
                                i++;
                        }


                        if (_isUnicode == false)
                        {
                            lstvRecv.Columns[0].Text = "HEX";
                            lstvRecv.Columns[1].Text = "BIN";
                            lstvRecv.Columns[2].Text = "ASCII";

                            foreach(string hex in hexes )
                            {
                                byte b = Convert.ToByte(hex, 16);
                                string bin = Convert.ToString(b, 2);
                                sb.Clear();
                                if (bin.Length < 8)
                                {
                                    int n = 8 - bin.Length;
                                    while (n > 0)
                                    {
                                        sb.Append("0");
                                        n--;
                                    }
                                }
                                sb.Append(bin);

                                string ascii;
                                if (b != 0x20)
                                    ascii = Convert.ToChar(b).ToString();
                                else
                                    ascii = "空格";



                                ListViewItem item = new ListViewItem(hex);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, sb.ToString());
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item, ascii);
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);
                            }
                        }
                        else
                        {
                            lstvRecv.Columns[0].Text = "HEX";
                            lstvRecv.Columns[1].Text = "BIN";
                            lstvRecv.Columns[2].Text = "Unicode";

                            if (hexes.Count % 2 != 0)
                                hexes.RemoveAt(hexes.Count - 1);

                            for(int i=0;i<hexes.Count;i+=2)
                            {
                                byte[] b = new byte[2];
                                b[0] = Convert.ToByte(hexes[i], 16);
                                b[1] = Convert.ToByte(hexes[i+1], 16);

                                sb.Clear();
                                for(int j=0;j<2;j++)
                                {
                                    string bin = Convert.ToString(b[j], 2);
                                    if (bin.Length < 8)
                                    {
                                        int n = 8 - bin.Length;
                                        while (n > 0)
                                        {
                                            sb.Append("0");
                                            n--;
                                        }
                                    }
                                    sb.Append(bin+" ");
                                }

                                string uni = Encoding.Unicode.GetString(b);

                                if (uni == " ")
                                    uni = "空格";

                                ListViewItem item = new ListViewItem(hexes[i] + " " + hexes[i + 1]);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, sb.ToString().Trim());
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item, uni);
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);
                            }
                        }
                        break;
                    }
                case CharTypes.BIN:
                    {
                        if (_isUnicode == false)
                        {
                            lstvRecv.Columns[0].Text = "BIN";
                            lstvRecv.Columns[1].Text = "HEX";
                            lstvRecv.Columns[2].Text = "ASCII";

                            string[] bins = str.Split(' ');

                            foreach (string bin in bins)
                            {
                                if (bin.Length != 8)
                                    continue;

                                byte b = Convert.ToByte(bin, 2);
                                string hex = string.Format("{0:X2}", b);

                                string ascii;
                                if (b != 0x20)
                                    ascii = Convert.ToChar(b).ToString();
                                else
                                    ascii = "空格";

                                ListViewItem item = new ListViewItem(bin);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, hex);
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item, ascii);
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);
                            }


                        }
                        else
                        {
                            lstvRecv.Columns[0].Text = "BIN";
                            lstvRecv.Columns[1].Text = "HEX";
                            lstvRecv.Columns[2].Text = "Unicode";

                            List<string> bins = new List<string>(str.Trim().Split(' '));

                            for (int i = 0; i < bins.Count; )
                            {
                                if (bins[i].Length != 8)
                                    bins.RemoveAt(i);
                                else
                                    i++;
                            }
                            if (bins.Count % 2 != 0)
                                bins.RemoveAt(bins.Count - 1);

                            for (int i = 0; i < bins.Count;i+=2 )
                            {
                                string hex;
                                byte[] b = new byte[2];
                                b[0]=Convert.ToByte(bins[i], 2);
                                b[1]=Convert.ToByte(bins[i+1], 2);

                                hex = string.Format("{0:X2} {1:X2}", b[0], b[1]);

                                string uni = Encoding.Unicode.GetString(b);

                                if (uni == " ")
                                    uni = "空格";

                                ListViewItem item = new ListViewItem(bins[i] + " " + bins[i + 1]);
                                ListViewItem.ListViewSubItem subItem1 = new ListViewItem.ListViewSubItem(item, hex);
                                ListViewItem.ListViewSubItem subItem2 = new ListViewItem.ListViewSubItem(item,uni);
                                item.SubItems.Add(subItem1);
                                item.SubItems.Add(subItem2);
                                items.Add(item);
                            }

                               
                        }
                        break;
                    }
            }
            if (items.Count > 0)
                lstvRecv.Items.AddRange(items.ToArray());
            lstvRecv.EndUpdate();
        }

        private void tmrTraffic_Tick(object sender, EventArgs e)
        {
            if(_Bps>50000)
            {
                if(_DontAskStopRecvDueToTraffic == false)
                {
                    tmrTraffic.Enabled = false;
                    if (MessageBox.Show("检测到串口上的大量数据。这可能导致程序响应速度降低或无法响应。是否停止接收数据？", "大量数据", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        btnOpenPort_Click(null, null);
                    }
                    else
                    {
                        _DontAskStopRecvDueToTraffic = true;
                    }
                    tmrTraffic.Enabled = true;
                }
            }

            lblTraffic.Text = _Bps.ToString();
            _Bps = 0;
        }

        delegate void FlashCompleteCallback();
        FlashCompleteCallback FlashCompleteHandler;

        void FlashComplete()
        {
            lblFlashEsp8266.Visible = false;
            pnlFlash.Enabled = true;
            btnStartFlash.Text = "开始";
            btnStartFlash.Enabled = true;
            pgbFlashEsp8266.Style = ProgressBarStyle.Continuous;
            pgbFlashEsp8266.Value = 100;

            if (serialPort.IsOpen)
                ClosePort();

            // 重新打开端口，且注册数据到达事件
            OpenPort(Convert.ToInt32(cbbBaudRate.Text),true);
        }

        private void btnStartFlash_Click(object sender, EventArgs e)
        {
            if(btnStartFlash.Text=="开始")
            {
                if (File.Exists(txbImg1Path.Text) == false || File.Exists(txbImg2Path.Text) == false)
                {
                    MessageBox.Show("固件选择错误");
                    return;
                }

                if (cbbPortName.SelectedIndex < 0)
                {
                    MessageBox.Show("还没有选择端口");
                    return;
                }

                btnStartFlash.Text = "终止";

                SaveFirmwares();

                

                // 如果当前串口是打开的，则先关闭一下
                if (serialPort.IsOpen)
                    ClosePort();

                // 重新打开端口，且不注册数据到达事件
                if (ckbDownloadInHighSpeed.Checked == false)
                    OpenPort(Convert.ToInt32(cbbBaudRate.Text), false);
                else
                    OpenPort(921600, false);

                if (serialPort.IsOpen == false)
                    serialPort.Open();

                pnlFlash.Enabled = false;

                lblFlashEsp8266.Visible = true;

                System.Threading.Thread thd = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
                {
                    FlashCompleteHandler = new FlashCompleteCallback(FlashComplete);

                    if (_Esp8266.Connect(serialPort))
                    {
                        lblFlashEsp8266.Text = _Esp8266.ReadMacAddr();
                        byte[] img1 = File.ReadAllBytes(txbImg1Path.Text);
                        _Esp8266.FlashDownload(img1, 0x00000, false);

                        System.Threading.Thread.Sleep(1000);

                        byte[] img2 = File.ReadAllBytes(txbImg2Path.Text);
                        _Esp8266.FlashDownload(img2, 0x40000, true);
                        _Esp8266.FlashDownloadFinish(true);
                    }

                    Invoke(FlashCompleteHandler);
                }));

                thd.IsBackground = true;
                thd.Start();
            }
            else
            {
                _Esp8266.Terminate();
                btnStartFlash.Enabled = false;
            }
            

            


           
        }

        private void Esp_Esp8266FlashStateChanged(ESP8266.Esp8266FlashStates state, object info)
        {
            this.Invoke(new MethodInvoker(() => 
            {
                switch (state)
                {
                    case ESP8266.Esp8266FlashStates.Connecting:
                        {
                            lblFlashEsp8266.Text = string.Format("正在查找 ESP8266（第{0}次）...", info);
                            pgbFlashEsp8266.Style = ProgressBarStyle.Marquee;
                            break;
                        }
                    case ESP8266.Esp8266FlashStates.Erasing:
                    case ESP8266.Esp8266FlashStates.Failed:
                        {
                            lblFlashEsp8266.Text ="操作中：" +info as string;
                            break;
                        }
                    case ESP8266.Esp8266FlashStates.Programming:
                        {
                            pgbFlashEsp8266.Style = ProgressBarStyle.Continuous;
                            lblFlashEsp8266.Text = "正在写入...";
                            pgbFlashEsp8266.Value = (int)info;
                            break;
                        }
                }

                lblFlashEsp8266.Invalidate();
            }));
        }

        private void btnOpenImg1_Click(object sender, EventArgs e)
        {
            if(openFileDialog1.ShowDialog()==DialogResult.OK)
            {
                txbImg1Path.Text = openFileDialog1.FileName;
                txbImg1Path.BackColor = Color.LightGreen;
                txbImg1Path.ForeColor = Color.Black;
            }
        }

        private void btnOpenImg2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                txbImg2Path.Text = openFileDialog1.FileName;
                txbImg2Path.BackColor = Color.LightGreen;
                txbImg2Path.ForeColor = Color.Black;
            }
        }
    }
}

